/*
 * Copyright (c) 2025 iSOFT INFRASTRUCTURE SOFTWARE CO., LTD.
 * easyAda is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *          http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */

#include <arch/context.h>
#include <arch/cpu.h>
#include <core/signal.h>
#include <core/pbuddy.h>
#include <core/task.h>
#include <core/schedule.h>
#include <core/dprintf.h>
#include <plat/config.h>
#include <libc/errno.h>
#include <caps/cnode.h>
#include <plat/irqn.h>

static uintptr_t common_func = 0;

/**
 * @brief   get the address of the function pointer
 *
 * @return  void *  the address pointed to by the function pointer
 *
 */
static uintptr_t get_common_func(void)
{
    return common_func;
}

/**
 * @brief   set the function pointer to the specified address
 *
 * @param   func   a pointer to the function pointer
 *
 */
static void set_common_func(uintptr_t func)
{
    common_func = func;
}

/**
 * @brief   get the signal type with the highest priority signal number from a 64-bit bit map
 *
 * @param   map  a 64-bit unsigned integer representing the bit map
 *
 * @return  the position of the most significant set bit
 */
static int32_t get_hp_sig_num(uint64_t bit_map)
{
    if (bit_map == 0UL) {
        return INVALID_PRIORITY;
    } else {
        bit_map &= ((~bit_map) + 1UL);
        return ffs64_msb(bit_map);
    }
}

/**
 * verify that there are any installed non-real-time signals
 *
 * @param tid       a pointer to the task control block
 * @param sig_num   the signal number to check for installation
 *
 * @return          true if the signal is installed (active or nested), false otherwise
*/
static bool is_nrt_sig_installed(tcb_t *tid, int32_t sig_num)
{
    sig_set_t mask     = sig_mask(sig_num);
    sig_cb_t *sig_info = task_get_scb(tid);

    if (task_get_state(tid) == TASK_DEAD) {
        return true;
    }

    if ((sig_num < SIG_NRT_MIN) || (sig_num > SIG_NRT_MAX)) {
        return false;
    }

    if (((mask & sig_info->sig_rec_map) != 0UL) || ((mask & sig_info->sig_nest_map) != 0UL)) {
        return true;
    }

    return false;
}

/**
 * @brief   get the signal control block associated with the current task
 *
 * @param   tid       pointer to the task control block (TCB) of the task
 * @param   sig_num   the signal number to be handled
 * @param   loop_cnt  loop count or iteration for signal processing
 */
static void sig_save_task_context(tcb_t *tid, int32_t sig_num, int32_t loop_cnt)
{
    context_set_entry(task_get_context(tid), (uint64_t)((uint64_t *)get_common_func()));
    context_set_reg_param(task_get_context(tid), (uint64_t)sig_num, (uint64_t)loop_cnt, 0, 0, 0, 0, 0, 0);
}

/**
 * @brief   check whether a given signal is part of the specified signal set
 *
 * @param   pSet     a pointer to the signal set to be checked
 * @param   sig_num  the signal number to be checked for membership in the set
 *
 * @return  bool     true if the signal is a member of the set, false if not
 */
static bool sig_is_member(const sig_set_t *p_set, int32_t sig_num)
{
    sig_set_t mask = sig_mask(sig_num);

    if (mask != 0UL) {
        return ((*p_set & mask) != 0UL);
    }

    return false;
}

/**
 * @brief   install a signal for a specific task
 *
 * @param   tid     a pointer to the task control block of the task to which the signal is to be installed
 * @param   sig_num  the signal number to be installed
 */
static void sig_install(tcb_t *tid, int32_t sig_num)
{
    sig_cb_t *sig_info = task_get_scb(tid);
    sig_set_t mask     = sig_mask(sig_num);

    if ((sig_num < SIG_NRT_MIN) || (sig_num > SIG_RT_MAX)) {
        return;
    }

    if (sig_num <= SIG_NRT_MAX) {
        sig_info->sig_rec[SIG_INDEX(sig_num)] = 1U;
        sig_info->sig_rec_map |= mask;
    } else {
        sig_info->sig_rec[SIG_INDEX(sig_num)] += 1U;
        sig_info->sig_rec_map |= mask;
    }
}

/**
 * @brief   send a signal to a task
 *
 * @param   tid     a pointer to the task control block of the task that will receive the signal
 * @param   sig_num  the signal number to be delivered or queued
 */
static void sig_ea_kill(tcb_t *tid, int32_t sig_num)
{
    tcb_t    *p_current = current();
    sig_cb_t *sig_info  = task_get_scb(tid);

    if (p_current != tid) {
        sig_install(tid, sig_num);
        sig_info->sig_handle_status |= SIG_INSTALLED;
    } else {
        sig_save_task_context(p_current, sig_num, SINGLE_TIME);
    }
}

/**
 * @brief   detach a task and mark it as ready to run
 *
 * @param   tid  a pointer to the task control block of the task
 */
static void sig_task_detach_and_ready(tcb_t *tid)
{
    sig_cb_t *sig_info = task_get_scb(tid);

    if ((task_get_state(tid) == TASK_DEAD) || (task_get_state(tid) == TASK_READY) ||
        (task_get_state(tid) == TASK_RUNNING)) {
        return;
    }

    sig_info->task_state = task_get_state(tid);

    schedule_detach(tid);
    schedule_attach_ready(tid);
}

/**
 * @brief   handle the signal kill request for a specific task
 *
 * @param   tid     a pointer to the task control block of the task to be killed
 * @param   sig_num  the signal number to be handled
 */
static void sig_kill_handle(tcb_t *tid, int32_t sig_num)
{
    uint16_t  status    = task_get_state(tid);
    tcb_t    *p_current = current();
    sig_cb_t *sig_info  = task_get_scb(tid);

    sig_info->sig_handle_status |= SIG_IPI_KILL;

    if (true == is_nrt_sig_installed(tid, sig_num)) {
        return;
    }

    if ((status == TASK_READY) || (status == TASK_RUNNING)) {
        if ((sig_info->sig_handle_status & SIG_USER_HANDLE) == SIG_USER_HANDLE) {
            /* nested interrupts */
            if (sig_num < sig_info->sig_handling_no) {
                /*
                 * the priority of the incoming signal is higher than the priority
                 * of the current interrupt service routine (ISR)
                 */
                sig_info->sig_handling_no = sig_num;

                /* save the context of the interrupt service routine (ISR) */
                (void)memcpy(&sig_info->sig_irq_context[SIG_INDEX(sig_num)], &p_current->context, sizeof(context_t));

                sig_info->sig_nest_map |= sig_mask(sig_num);

                sig_save_task_context(p_current, sig_num, SINGLE_TIME);
                sig_info->sig_handle_status |= SIG_NESTED;
            } else if (sig_num > sig_info->sig_handling_no) {
                sig_install(tid, sig_num);
                sig_info->sig_handle_status |= SIG_LP_INSTALLED;
            } else if ((sig_num >= SIG_RT_MIN) && (sig_num <= SIG_RT_MAX)) {
                sig_install(tid, sig_num);
                sig_info->sig_handle_status |= SIG_LP_INSTALLED;
            } else {
                /* no need to record non-real-time signal with the same priority */
            }
        } else {
            (void)memcpy(&sig_info->sig_task_context, &tid->context, sizeof(context_t));
            sig_install(tid, sig_num);
            sig_info->sig_handle_status |= SIG_INSTALLED;
        }
    } else {
        (void)memcpy(&sig_info->sig_task_context, &tid->context, sizeof(context_t));
        sig_task_detach_and_ready(tid);
        sig_install(tid, sig_num);
        sig_info->sig_handle_status |= SIG_INSTALLED;
    }
}

#ifdef CONFIG_ENABLE_SMP
/**
 * @brief   handle Inter-Processor Interrupt (IPI) signals
 *
 * @param   data    a pointer to the IPI data structure
 */
void ipi_signal_handler(ipi_data_t *data)
{
    tcb_t  *send_task = (tcb_t *)data->i_data1;
    int32_t sig_num   = (int32_t)data->i_data2;

    switch (data->i_type2) {
        case IPI_SIGNAL_KILL:
            sig_kill_handle(send_task, sig_num);
            break;
        default:
            dprintf("invalid signale ipi type:%d \n", data->i_type2);
            break;
    }
}
#endif

/**
 * @brief   check and handle current signal
 */
void sig_check_and_handle(void)
{
    sig_set_t mask     = 0;
    int32_t   sig_num  = 0;
    sig_cb_t *sig_info = task_get_scb(current());

    if ((sig_info->sig_handle_status & SIG_INSTALLED) == 0UL) {
        return;
    }

    sig_num = get_hp_sig_num(sig_info->sig_rec_map);

    if (sig_num == INVALID_PRIORITY) {
        return;
    }

    mask = sig_mask_fast(sig_num);

    if (sig_info->sig_rec[SIG_INDEX(sig_num)] == 0U) {
        sig_info->sig_rec_map &= ~mask;
        return;
    }

    if ((sig_info->sig_mask_map & mask) != 0UL) {
        return;
    }

    sig_save_task_context(current(), sig_num, (int32_t)sig_info->sig_rec[SIG_INDEX(sig_num)]);

    sig_info->sig_rec[SIG_INDEX(sig_num)] = 0;
    sig_info->sig_rec_map &= ~mask;
    sig_info->sig_handle_status = SIG_USER_HANDLE;
    sig_info->sig_handling_no   = sig_num;
}

/**
 * @brief   initialize a signal list
 *
 * @param   sig_list    a pointer to the list head that will be initialized
 */
static void signal_list_init(list_t *sig_list)
{
    list_init(sig_list);
}

/**
 * @brief   wake up a task that was blocked due to a signal timeout
 *
 * @param   tid a pointer to the task control block of the task to be woken up
 */
void sig_timeout_wake(tcb_t *tid)
{
    schedule_detach_block(tid);
    task_set_retcode(tid, ETIMEDOUT);
}

/**
 * @brief   retrieve the highest priority signal from nested, pending, or received signals
 *
 * @param   sig_hp  pointer to a variable where the highest priority signal value will be stored
 *
 * @return  SIG_NEST_HP if the highest priority is from the nested signal map
 *          SIG_REC_HP if the highest priority is from the received signal map
 *          SIG_PEND_HP if the highest priority is from the pending signal map
 *          SIG_NO if no valid signal priority is found
 */
static sig_type get_hp_type(int32_t *sig_hp)
{
    sig_cb_t *sig_info = task_get_scb(current());

    uint64_t nest_map = sig_info->sig_nest_map;
    uint64_t rec_map  = sig_info->sig_rec_map;
    uint64_t pend_map = sig_info->sig_pend_map;
    uint64_t mask     = sig_info->sig_mask_map;

    int32_t nest_hp = 0;
    int32_t rec_hp  = 0;
    int32_t pend_hp = 0;

    if ((nest_map == 0UL) && (rec_map == 0UL) && (pend_map == 0UL)) {
        *sig_hp = INVALID_PRIORITY;
        return SIG_NO;
    }

    nest_hp = get_hp_sig_num(nest_map);
    rec_hp  = get_hp_sig_num(rec_map);

    pend_map &= ~mask;
    pend_hp = get_hp_sig_num(pend_map);

    if ((nest_hp <= rec_hp) && (nest_hp <= pend_hp)) {
        *sig_hp = nest_hp;
        return SIG_NEST_HP;
    } else if (rec_hp <= pend_hp) {
        *sig_hp = rec_hp;
        return SIG_REC_HP;
    } else {
        *sig_hp = pend_hp;
        return SIG_PEND_HP;
    }
}

/**
 * @brief   handle a nested signal by updating the signal context and clear the signal
 *
 * @param   sig_num  the signal number to be handled
 */
static void sig_nest_handle(int32_t sig_num)
{
    tcb_t    *p_current = current();
    sig_set_t mask      = sig_mask_fast(sig_num);
    sig_cb_t *sig_info  = task_get_scb(p_current);

    (void)memcpy(&p_current->context, &sig_info->sig_irq_context[SIG_INDEX(sig_num)], sizeof(context_t));
    sig_info->sig_nest_map &= ~mask;
}

/**
 * @brief  handle the signal reception by saving the current task's context
 *
 * @param   sig_num  the signal number to be handled
 */
static void sig_rec_handle(int32_t sig_num)
{
    sig_cb_t *sig_info = task_get_scb(current());
    sig_set_t mask     = 0;
    uint16_t  count    = 0;

    count = sig_info->sig_rec[SIG_INDEX(sig_num)];
    mask  = sig_mask_fast(sig_num);

    sig_save_task_context(current(), sig_num, (int32_t)count);

    sig_info->sig_rec[SIG_INDEX(sig_num)] = 0U;
    sig_info->sig_rec_map &= ~mask;
}

/**
 * @brief   handle the pending signal by saving the current task's context and clear the signal
 *
 * @param   sig_num  the signal number to be handled
 */
static void sig_pend_handle(int32_t sig_num)
{
    sig_cb_t *sig_info = task_get_scb(current());
    sig_set_t mask     = 0;

    mask = sig_mask_fast(sig_num);

    sig_save_task_context(current(), sig_num, SINGLE_TIME);

    sig_info->sig_pend_map &= ~mask;
}

/**
 * @brief   exit the signal handling routine and return to user mode
 *
 */
static void sig_exit_to_user_mode(void)
{
    tcb_t    *p_current       = current();
    sig_cb_t *sig_info        = task_get_scb(p_current);
    uint64_t  sleep_time_left = 0;

    (void)memcpy(&p_current->context, &sig_info->sig_task_context, sizeof(context_t));
    sig_info->sig_handle_status = SIG_DEFAULT;

    if ((sig_info->task_state == TASK_BLOCKED) || (sig_info->task_state == TASK_SLEEP_BLOCKED)) {
        task_set_retcode(p_current, EINTR);
    } else if (sig_info->task_state == TASK_SLEEP) {
        sleep_time_left = task_get_remaining_delay(p_current);
        task_set_retcode(p_current, sleep_time_left);
    } else {
        /* other task state */
    }

    sig_info->task_state = TASK_RUNNING;
}

/**
 * @brief   handle the exit from signal processing and determine the next action based on the signal type
 *
 */
static void sig_exit_handle(void)
{
    int32_t   hp_sig_num = 0;
    sig_cb_t *sig_info   = task_get_scb(current());
    sig_type  hp_type    = get_hp_type(&hp_sig_num);

    sig_info->sig_handle_status = SIG_RET_KERNEL;

    switch (hp_type) {
        case SIG_NO:
            sig_exit_to_user_mode();
            break;
        case SIG_NEST_HP:
            sig_nest_handle(hp_sig_num);
            sig_info->sig_handle_status &= (~SIG_INSTALLED);
            sig_info->sig_handle_status |= SIG_USER_HANDLE;
            break;
        case SIG_REC_HP:
            sig_rec_handle(hp_sig_num);
            sig_info->sig_handle_status &= (~SIG_INSTALLED);
            sig_info->sig_handle_status |= SIG_USER_HANDLE;
            break;
        case SIG_PEND_HP:
            sig_pend_handle(hp_sig_num);
            sig_info->sig_handle_status &= (~SIG_INSTALLED);
            sig_info->sig_handle_status |= SIG_USER_HANDLE;
            break;
        default:
            dprintf("invalid type:%d \n", hp_type);
            break;
    }
}

/**
 * @brief   initialize the signal handling system with the provided configuration
 *
 * @param cfg   a pointer to the configuration structure
 */
static void sig_init(op_signal_param_t *cfg)
{
    set_common_func(cfg->common_func);
}

/**
 * @brief   retrieve the first pending signal from the signal set
 *
 * @param sig_tcb   a pointer to the signal control block of the task
 * @param sigset    a pointer to the signal set
 *
 * @return          the signal number of the first pending signal found,
 *                  or SIG_ERROR if no pending signals exist
 */
static int32_t sig_pend_get(sig_cb_t *sig_tcb, const sig_set_t *sigset)
{
    int32_t   sig_num;
    sig_set_t bit_map;

    bit_map = *sigset & sig_tcb->sig_pend_map;

    sig_num = get_hp_sig_num(bit_map);

    if (sig_num == INVALID_PRIORITY) {
        return SIG_ERROR;
    }

    bit_map = sig_mask_fast(sig_num);

    sig_tcb->sig_pend_map &= ~bit_map;

    return sig_num;
}

/**
 * @brief   select the first pending signal that is not blocked by the signal mask
 *
 * @param sig_tcb   a pointer to the signal control block of the task
 * @param sig_num   a pointer to an integer where the signal number will be stored
 *
 * @return          true if a pending signal is found that is not blocked by the signal mask, false otherwise
 */
static bool sig_pend_select(sig_cb_t *sig_tcb, int32_t *sig_num)
{
    sig_set_t set = ~sig_tcb->sig_mask_map;
    int32_t   num = sig_pend_get(sig_tcb, &set);

    if (num != SIG_ERROR) {
        *sig_num = num;

        return true;
    }

    return false;
}

/**
 * @brief   modify the signal mask of the current task
 *
 * @param how       the action to perform on the signal mask
 * @param set       a pointer to the signal set to be used for the action
 * @param old_set   a pointer to where the old signal mask will be saved, if NULL, the old mask is not saved
 * @param sig_num   a pointer to an integer where the first pending signal will be stored
 *
 * @return          SIG_OK if no signal was unblocked
 *                  SIG_ERROR if an invalid operation is provided
 *                  true if a signal was unblocked and its handler should be run
 */
static int32_t sig_proc_mask_child(int32_t how, const sig_set_t *set, sig_set_t *old_set, int32_t *sig_num)
{
    sig_cb_t *sig_tcb  = task_get_scb(current());
    int32_t   ret_code = SIG_OK;

    if (old_set != NULL) {
        *old_set = sig_tcb->sig_mask_map;
    }

    if (set != NULL) {
        switch (how) {
            case SIG_BLOCK:
                sig_tcb->sig_mask_map |= *set;
                ret_code = SIG_OK;
                break;
            case SIG_UNBLOCK:
                sig_tcb->sig_mask_map &= ~*set;
                ret_code = ((sig_pend_select(sig_tcb, sig_num)) ? 1 : 0);
                break;
            case SIG_SETMASK:
                sig_tcb->sig_mask_map = *set;
                ret_code              = ((sig_pend_select(sig_tcb, sig_num)) ? 1 : 0);
                break;
            default:
                task_set_retcode(current(), EINVAL);
                ret_code = SIG_ERROR;
                break;
        }
    }

    return ret_code;
}

/**
 * @brief   modify the signal mask of the current task and handle signal processing
 *
 * @param how       the action to perform on the signal mask
 * @param set       a pointer to the signal set to be used for modifying the signal mask
 * @param old_set   a pointer to where the old signal mask will be saved, if NULL, the old mask is not saved
 *
 */
void sig_proc_mask(int32_t how, const sig_set_t *set, sig_set_t *old_set)
{
    tcb_t    *p_current = current();
    sig_cb_t *sig_info  = task_get_scb(p_current);
    int32_t   sig_num   = 0;

    sig_info->sig_handle_status |= SIG_SYSCALL;
    (void)memcpy(&sig_info->sig_task_context, &p_current->context, sizeof(context_t));

    if (sig_proc_mask_child(how, set, old_set, &sig_num) == 1L) {
        sig_save_task_context(p_current, sig_num, SINGLE_TIME);
    }
}

#ifdef CONFIG_ENABLE_SMP
/**
 * @brief   send an Inter-Processor Interrupt (IPI) to a target task to trigger a signal
 *
 * @param tid       a pointer to the task control block
 * @param sig_num   the signal number that will be sent to the target thread
 *
 */
static void sig_ipi_send(tcb_t *tid, int32_t sig_num)
{
    if (true == is_nrt_sig_installed(tid, sig_num)) {
        return;
    }

    ipi_data_t data;

    (void)memset(&data, 0x00, sizeof(ipi_data_t));
    data.i_type1     = (uint8_t)IPIDATA_SIGNAL_SEND;
    data.i_type2     = IPI_SIGNAL_KILL;
    data.i_data1     = (uint64_t)tid;
    data.i_data2     = (uint64_t)sig_num;
    data.i_sync_mode = (uint8_t)IPI_ASYNC_MODE;

    (void)send_ipi_all_mode((uint32_t)IRQN_SGI0, tid->affinity, &data, (uint64_t)IPI_SYNC_TIMEOUT);
}
#endif

/**
 * @brief   initialize a signal set with no signals included
 *
 * @param   pSet    a pointer to the signal set to initialize
 *
 */
static void sig_empty_set(sig_set_t *pSet)
{
    *pSet = 0;
}

/**
 * @brief   wakes up a task that is waiting for a signal
 *
 * @param tid       a pointer to the task control block
 * @param sig_num   the signal number to be sent to the waiting task
 */
static void sig_wakeup_task(tcb_t *tid, int32_t sig_num)
{
    op_signal_param_t *cfg      = ipcbuffer_get_op_struct(task_get_ipcbuffer(tid));
    sig_cb_t          *sig_info = task_get_scb(tid);

    tcb_t      *wait_task = NULL;
    resource_t *res       = NULL;

    res       = list_first_entry(&sig_info->wait_info.sig_wait, resource_t, s_list);
    wait_task = res->s_owner;

    if (wait_task == NULL) {
        return;
    }

    schedule_detach_block(wait_task);
    schedule_attach_ready(wait_task);

    sig_info->wait_info.sig_info.si_signo = sig_num;

    if (cfg->info != NULL) {
        (void)memcpy((sig_info_t *)cfg->info, &sig_info->wait_info.sig_info, sizeof(sig_info_t));
    }

    sig_empty_set(&sig_info->wait_info.sig_set);
}

/**
 * @brief   send a signal to a specific task
 *
 * @param tid       a pointer to the task control block
 * @param sig_num   the signal number to be sent to the target task
 *
 * @return          return SIG_OK to indicate the operation was successful
 */
void sig_kill(tcb_t *tid, int32_t sig_num)
{
    tcb_t    *p_current = current();
    sig_cb_t *sig_info  = task_get_scb(tid);
    sig_set_t mask      = sig_mask(sig_num);

    if (sig_is_member((const sig_set_t *)&sig_info->wait_info.sig_set, sig_num) == true) {
        sig_wakeup_task(tid, sig_num);
        return;
    }

    if ((sig_info->sig_mask_map & mask) != 0UL) {
        sig_info->sig_pend_map |= mask;
        return;
    }

    if (tid == p_current) {
        sig_ea_kill(tid, sig_num);
    } else {
        if (task_get_coreid(tid) == task_get_coreid(p_current)) {
            sig_task_detach_and_ready(tid);
            sig_ea_kill(tid, sig_num);
        } else {
#ifdef CONFIG_ENABLE_SMP
            sig_ipi_send(tid, sig_num);
#endif
        }
    }
}

/**
 * @brief   send a signal to a specific task identified by its capability
 *
 * @param cptr      a pointer to the capability representing the target task
 * @param sig_num   the signal number to be sent, which indicates the action
 *
 * @return          return SIG_OK if the signal is successfully sent,
 *                  or SIG_ERROR if the signal number is invalid
 */
static int32_t sig_task_kill(cptr_t cptr, int32_t sig_num)
{
    tcb_t        *p_current = current();
    capability_t *cap       = NULL;
    tcb_t        *send_task = NULL;

    if ((sig_num < MIN_SIG) || (sig_num > MAX_SIG)) {
        return SIG_ERROR;
    }

    cap = cnode_cptr_lookup(task_get_cnode(p_current), cptr, sizeof(unsigned long) * 8);

    send_task = (tcb_t *)cap_get_long_info(cap);

    if (task_get_state(send_task) == TASK_DEAD) {
        return SIG_ERROR;
    }

    send_task->sig_info.sig_handle_status |= SIG_SYSCALL;

    if (task_get_coreid(send_task) == task_get_coreid(p_current)) {
        if ((send_task == p_current) || ((send_task->sig_info.sig_handle_status & SIG_USER_HANDLE) == 0)) {
            (void)memcpy(&send_task->sig_info.sig_task_context, &send_task->context, sizeof(context_t));
        }
    }

    sig_kill(send_task, sig_num);

    return SIG_OK;
}

/**
 * @brief   wait for the specified signal set to trigger or time out
 *
 * @param set   the signal set (sig_set_t*) to wait for
 * @param usec  the timeout in microseconds
 */
static void sig_time_wait(sig_set_t *set, uint64_t usec)
{
    tcb_t      *p_current = current();
    sig_cb_t   *sig_info  = task_get_scb(p_current);
    sig_wait_t *wait_info = &sig_info->wait_info;

    if (usec == SIG_NO_WAIT) {
        task_set_retcode(p_current, EAGAIN);
        return;
    }

    wait_info->sig_set = *set;
    signal_list_init(&wait_info->sig_wait);

    schedule_attach_block(p_current, &wait_info->sig_wait, RESOURCE_SIG);
    schedule_attach_sleep(p_current, usec);
}

/**
 * @brief   handle various signal-related commands
 *
 * @param cmd    the command indicating the specific signal operation to perform
 * @param cfg    a pointer to the signal configuration structure containing necessary parameters
 */
void sig_handle(uint64_t cmd, op_signal_param_t *cfg)
{
    switch (cmd) {
        case CAP_PTHEAD_KILL:
            (void)sig_task_kill(cfg->cptr, cfg->sig_num);
            break;
        case CAP_SIGNAL_INIT:
            sig_init(cfg);
            break;
        case CAP_SIGNAL_EXIT:
            sig_exit_handle();
            break;
        case CAP_SIGNAL_PROCMASK:
            sig_proc_mask(cfg->how, (const sig_set_t *)cfg->set, cfg->old_set);
            break;
        case CAP_SIGNAL_TIME_WAIT:
            sig_time_wait(cfg->set, cfg->timeout);
            break;
        default:
            dprintf("invalid cmd:%d \n", cmd);
            break;
    }
}
